#include "smtechnique_impl.h"
#include "shadermanager.h"
#include "scenemanager.h"
#include "renderop.h"
#include <assert.h>

namespace ZH
{
	SpotSMTechnique::SpotSMTechnique(LPDIRECT3DDEVICE9 device, const D3DLIGHT9& light) : SMTechnique(light)
	{
		HRESULT hr = device->CreateTexture(1024, 1024, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT,
			&m_pShadowTexture, NULL);
		assert(SUCCEEDED(hr));
		hr = device->CreateDepthStencilSurface(1024, 1024, D3DFMT_D24S8, D3DMULTISAMPLE_NONE,
			0, true, &m_pDepthSurface, NULL);
		assert(SUCCEEDED(hr));

		m_PassCaster.depth_check = true;
		m_PassCaster.depth_write = true;

		m_PassReciver.depth_check = true;
		m_PassReciver.depth_write = false;
		m_PassReciver.source_blend_factor = D3DBLEND_SRCALPHA;
		m_PassReciver.dest_blend_factor = D3DBLEND_INVSRCALPHA;
	}

	SpotSMTechnique::~SpotSMTechnique()
	{
		m_pDepthSurface->Release();
		m_pDepthSurface = NULL;
		m_pShadowTexture->Release();
		m_pShadowTexture = NULL;
	}

	D3DXMATRIX SpotSMTechnique::GetViewProjMatrix()const
	{
		D3DXMATRIX view_matrix;
		D3DXMATRIX proj_matrix;
		D3DXVECTOR3 at = D3DXVECTOR3(m_targetLight.Position) + D3DXVECTOR3(m_targetLight.Direction) * 1.0f;
		D3DXMatrixLookAtLH(&view_matrix, &D3DXVECTOR3(m_targetLight.Position), &at,
			&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
		D3DXMatrixPerspectiveFovLH(&proj_matrix, m_targetLight.Phi, 1.0f, 0.1f, 1000.0f);
		return view_matrix * proj_matrix;
	}

	bool SpotSMTechnique::RenderCaster(LPDIRECT3DDEVICE9 device, RenderQueue::VECTOR_RENDEROP& ops)
	{
// 		Shader* v_s = ShaderManager::getSingleton().GetShader(Shader::emTypeVertex, "ShadowCaster_Vp");
// 		assert(v_s);
// 		Shader* p_s = ShaderManager::getSingleton().GetShader(Shader::emTypeFragment, "ShadowCaster_Fp");
// 		assert(p_s);
// 
// 		ShaderParam* v_s_p = v_s->GetShaderParam();
// 		LPDIRECT3DSURFACE9 pOldSurface = NULL;
// 		LPDIRECT3DSURFACE9 pOldDepth = NULL;
// 		LPDIRECT3DSURFACE9 pShadow = NULL;
// 		
// 		m_pShadowTexture->GetSurfaceLevel(0, &pShadow);
// 		device->GetRenderTarget(0, &pOldSurface);
// 		device->GetDepthStencilSurface(&pOldDepth);
// 
// 		device->SetRenderTarget(0, pShadow);
// 		device->SetDepthStencilSurface(m_pDepthSurface);
// 		pShadow->Release();
// 
// 		D3DXMATRIX view_proj = GetViewProjMatrix();
// 		
// 		device->BeginScene();
// 		{
// 			device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
// 				0xFFFFFFFF, 1.0f, 0);
// 
// 			v_s->BindDevice(device);
// 			p_s->BindDevice(device);
// 
// 			v_s_p->SetMatrix(device, "view_proj_matrix", &view_proj);
// 
// 			SceneManager::getSingleton().SetPass(m_PassCaster);
// 
// 			Renderable::VECTOR_RENDEROP::iterator end = ops.end();
// 			for (Renderable::VECTOR_RENDEROP::iterator beg = ops.begin(); beg != end; ++ beg)
// 			{
// 				RenderOp& op = *beg;
// 				if (op.pass->cast_shadow)
// 				{
// 					v_s_p->SetMatrix(device, "world_matrix", &op.matrix);
// 					op.mesh->DrawPrimitive(device);
// 				}
// 			}
// 			device->SetVertexShader(NULL);
// 			device->SetPixelShader(NULL);
// 		}
// 		device->EndScene();
// 
// 		device->SetRenderTarget(0, pOldSurface);
// 		pOldSurface->Release();
// 		device->SetDepthStencilSurface(pOldDepth);
// 		pOldDepth->Release();

// 		static bool bSave = false;
// 		if (false == bSave)
// 		{
// 			bSave = true;
// 			D3DXSaveTextureToFileA("shaodw_texture.tga", D3DXIFF_TGA, m_pShadowTexture, NULL);
// 		}

		return true;
	}

	bool SpotSMTechnique::RenderReciver(LPDIRECT3DDEVICE9 device, RenderQueue::VECTOR_RENDEROP& ops)
	{
// 		const Camera& camera = SceneManager::getSingleton().GetCamera();
// 		D3DXMATRIX camera_view_proj = (*camera.GetViewMatrix()) * (*camera.GetProjMatrix());
// 		D3DXMATRIX shadow_view_porj = GetViewProjMatrix();
// 		Shader* v_s = ShaderManager::getSingleton().GetShader(Shader::emTypeVertex, "ShaodwReceiver_Vp");
// 		Shader* p_s = ShaderManager::getSingleton().GetShader(Shader::emTypeFragment, "ShadowReciver_Fp");
// 		assert(v_s && p_s);
// 		ShaderParam* v_s_p = v_s->GetShaderParam();
// 		ShaderParam* p_s_p = p_s->GetShaderParam();
// 
// 		D3DXMATRIX view_matrix;
// 		D3DXVECTOR3 at = D3DXVECTOR3(m_targetLight.Position) + D3DXVECTOR3(m_targetLight.Direction);
// 		D3DXMatrixLookAtLH(&view_matrix, &D3DXVECTOR3(m_targetLight.Position), &at, &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
// 		D3DXMATRIX proj_matrix;
// 		D3DXMatrixPerspectiveFovLH(&proj_matrix, m_targetLight.Phi, 640.0f / 480.0f, 0.1f, 1000.0f);
// //		camera_view_proj = view_matrix * proj_matrix;
// 
// 		device->BeginScene();
// 		{
// 			device->SetTexture(0, m_pShadowTexture);
// 			device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
// 			device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
// 			device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
// 			device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
// 			device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
// 
// 			v_s->BindDevice(device);
// 			p_s->BindDevice(device);
// 
// 			v_s_p->SetMatrix(device, "worldViewProj", &camera_view_proj);
// 			v_s_p->SetMatrix(device, "texViewProj", &shadow_view_porj);
// 
// 			SceneManager::getSingleton().SetPass(m_PassReciver);
// 
// 			Renderable::VECTOR_RENDEROP::iterator end = ops.end();
// 			for (Renderable::VECTOR_RENDEROP::iterator beg = ops.begin(); beg != end; ++ beg)
// 			{
// 				RenderOp& op = *beg;
// 				if (op.pass->recive_shadow)
// 				{
// 					v_s_p->SetMatrix(device, "world_matrix", &op.matrix);
// 					op.mesh->DrawPrimitive(device);
// 				}
// 			}
// 			device->SetVertexShader(NULL);
// 			device->SetPixelShader(NULL);
// 			device->SetTexture(0, NULL);
// 		}
// 		device->EndScene();

		return true;
	}
}	// end of namespace ZH
